/*******************************************************************************
 * Copyright (c) 2016 Avaloq Group AG and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Avaloq Group AG - initial API and implementation
 *******************************************************************************/
package com.avaloq.tools.ddk.xtext.formatting.locators;

import org.eclipse.xtext.formatting.impl.AbstractFormattingConfig;
import org.eclipse.xtext.formatting.impl.FormattingConfig;

import com.avaloq.tools.ddk.xtext.formatting.ExtendedLine;
import com.avaloq.tools.ddk.xtext.formatting.ExtendedLineEntry;
import com.avaloq.tools.ddk.xtext.formatting.SpaceEntry;


/**
 * Column locator capable of handling columns that spans over multiple lines. It is used as a marker to indicate the content that should be aligned as a column.
 * If the cursor of a line, to which an entry is to be added, is to the left of the specified column,
 * padding must be added. The method {@link #computeSpace(ExtendedLine, ExtendedLineEntry)} will calculate the
 * necessary amount of padding required.
 */
public class FixedLocator extends AbstractFormattingConfig.ElementLocator implements ISpaceLocator {

  private int column;
  /**
   * Determines if column has fixed position or might be shifted after the items that occupies the intended column location.
   */
  private final boolean fixed;
  /**
   * Determines is column location is relative to the current indentation or absolute.
   */
  private final boolean relative;
  /**
   * Determines if column should start in the same line as the multi-row column that preceeds the current column or in the new line.
   */
  private final boolean nobreak;

  public int getColumn() {
    return column;
  }

  public void setColumn(final int column) {
    this.column = column;
  }

  public boolean isFixed() {
    return fixed;
  }

  public boolean isRelative() {
    return relative;
  }

  public boolean isNoBreak() {
    return nobreak;
  }

  /**
   * Creates a new column locator.
   *
   * @param column
   *          the column
   * @param formattingConfig
   *          the enclosing formatting config
   * @param fixed
   *          determines if column has fixed position or might be shifted after the items that occupies the intended column location
   * @param relative
   *          determines is column location is relative to the current indentation or absolute
   * @param nobreak
   *          determines if column should start in the same line as the multi-row column that preceeds the current column or in the new line.
   */
  public FixedLocator(final FormattingConfig formattingConfig, final int column, final boolean fixed, final boolean relative, final boolean nobreak) { // NOPMD
    // CallSuperInConstructor
    // - false
    // positive by PMD
    formattingConfig.super();
    this.column = column;
    this.fixed = fixed;
    this.relative = relative;
    this.nobreak = nobreak;
  }

  /**
   * Gets the padding for an entry. When the padding is prepended to the value of the entry,
   * the entry will be at the character position specified in the constructor.
   *
   * @param line
   *          the line containing entry / to which entry is to be added
   * @param entry
   *          the entry to be padded
   * @return the padding required to ensure entry will occupy space after the specified column
   */
  @Override
  public String computeSpace(final ExtendedLine line, final ExtendedLineEntry entry) {
    int absoluteLineLength = line.getAbsoluteLineLength(entry);
    int distanceFromLastLineCharacterToColumn = entry.getColumnIndent() - absoluteLineLength;
    int predecessorIndex = line.findPredecessorOrLastEntryIndex(entry);
    ExtendedLineEntry precedingEntry = line.getEntries().get(predecessorIndex);

    int precedingEntryLength = 0;
    if (!precedingEntry.equals(entry)) {
      precedingEntryLength = precedingEntry.getValue().length();
    }
    boolean isGoingToBeShifted = distanceFromLastLineCharacterToColumn < 1 && absoluteLineLength > 0 && precedingEntryLength > 0;
    if ((entry.isFixedLocatorClosing() || entry.isFixedLocatorOpening()) && isGoingToBeShifted) {
      distanceFromLastLineCharacterToColumn = 1;
    }

    return SpaceEntry.createPadding(distanceFromLastLineCharacterToColumn);
  }

  @Override
  public AggregationPolicy getPolicy() {
    return AggregationPolicy.COMBINED_MAXIMUM;
  }

}
